//
//  UIImage+YHExtension.swift
//  Adorbee
//
//  Created by amovision on 2024/11/26.
//

import CoreGraphics
import UIKit

public extension UIImage {
  var width: CGFloat { size.width }
  var height: CGFloat { size.height }
  var whRatio: CGFloat { height == 0 ? 0 : width/height }
  
  internal func tint(_ color: UIColor) -> UIImage {
    let drawRect = CGRect(origin: .zero, size: size)

    let format = UIGraphicsImageRendererFormat()
    format.scale = scale
    return UIGraphicsImageRenderer(size: size, format: format).image { context in
      color.setFill()
      context.fill(drawRect)
      draw(in: drawRect, blendMode: .destinationIn, alpha: 1.0)
    }
  }
  
  internal func resize(_ size: CGSize) -> UIImage {
    if size.width <= 0 || size.width <= 0 { return self }
    let format = UIGraphicsImageRendererFormat()
    format.scale = scale
    return UIGraphicsImageRenderer(size: size, format: format).image { _ in
      draw(in: CGRect(origin: .zero, size: size))
    }
  }
  
  internal convenience init(color: UIColor, size: CGSize) {
    let format = UIGraphicsImageRendererFormat()
    format.scale = 1
    guard let image = UIGraphicsImageRenderer(size: size, format: format).image(actions: { context in
      color.setFill()
      context.fill(context.format.bounds)
    }).cgImage else {
      self.init()
      return
    }
    self.init(cgImage: image)
  }
  
  class func named(_ src: Any?, size: CGSize = .zero, color: UIColor? = nil) -> UIImage? {
    guard let src else { return nil }
    let image: UIImage? = if let name = src as? String {
      if let img = UIImage(named: name) { img }
      else if let img = UIImage(systemName: name) { img }
      else { nil }
    } else if let img = src as? UIImage { img }
    else { nil }
    return if let color {
      if size != .zero {
        image?.resize(size).tint(color)
      } else {
        image?.tint(color)
      }
    } else {
      if size != .zero {
        image?.resize(size)
      } else {
        image
      }
    }
  }
    
  enum GradientDirection { case leftToRight, topToBottom, leftToBottom, leftToTop }
  static func gradient(_ direction: UIImage.GradientDirection = .leftToRight, colors: [UIColor],
                       size: CGSize,
                       locations: [CGFloat]?) -> UIImage?
  {
    // 转换颜色为CGColor
    let cgColors = colors.map { $0.cgColor }
        
    // 开始绘制上下文
    UIGraphicsBeginImageContextWithOptions(size, false, 1)
    guard let context = UIGraphicsGetCurrentContext() else { return nil }
        
    context.saveGState()
        
    // 创建渐变
    guard let colorSpace = colors.last?.cgColor.colorSpace,
          let gradient = CGGradient(colorsSpace: colorSpace,
                                    colors: cgColors as CFArray,
                                    locations: locations) else { return nil }
        
    // 确定起始点和结束点
    var start: CGPoint
    var end: CGPoint
        
    switch direction {
    case .topToBottom:
      start = CGPoint(x: size.width/2, y: 0)
      end = CGPoint(x: size.width/2, y: size.height)
            
    case .leftToRight:
      start = CGPoint(x: 0, y: size.height/2)
      end = CGPoint(x: size.width, y: size.height/2)
            
    case .leftToBottom:
      start = CGPoint(x: 0, y: 0)
      end = CGPoint(x: size.width, y: size.height)
            
    case .leftToTop:
      start = CGPoint(x: 0, y: size.height)
      end = CGPoint(x: size.width, y: 0)
    }
        
    // 绘制渐变
    context.drawLinearGradient(gradient,
                               start: start,
                               end: end,
                               options: [.drawsBeforeStartLocation, .drawsAfterEndLocation])
        
    // 获取图片
    let image = UIGraphicsGetImageFromCurrentImageContext()
        
    // 清理资源
    context.restoreGState()
    UIGraphicsEndImageContext()
        
    return image
  }
    
  static func gradient(_ direction: UIImage.GradientDirection = .leftToRight, colors: [UIColor],
                       size: CGSize) -> UIImage?
  {
    let locations: [CGFloat] = if colors.count <= 1 { [0] }
    else {
      (0 ..< colors.count).map { (1/(CGFloat(colors.count) - 1)) * CGFloat($0) }
    }
    return gradient(direction, colors: colors, size: size, locations: locations)
  }

  enum CICodeGeneratorType: String {
    case aztecCode = "CIAztecCodeGenerator"
    case code128Barcode = "CICode128BarcodeGenerator"
    case PDF417Barcode = "CIPDF417BarcodeGenerator"
    case QRCode = "CIQRCodeGenerator"
  }

  /// 异步生成二维码/条形码
  /// - Parameters:
  ///   - type: 码类型（二维码/条形码等）
  ///   - string: 要编码的字符串
  ///   - size: 生成图像的尺寸
  ///   - qrColor: 码的颜色
  ///   - bkColor: 背景颜色
  ///   - completion: 生成完成的回调，在主线程执行
  static func createCodeAsync(
    type: UIImage.CICodeGeneratorType = .QRCode,
    string: String,
    size: CGSize,
    qrColor: UIColor = .black,
    bkColor: UIColor = .white,
    completion: @escaping (UIImage?) -> Void
  ) {
    DispatchQueue.global(qos: .userInitiated).async {
      let resultImage = self.createCodeSync(
        type: type,
        string: string,
        size: size,
        qrColor: qrColor,
        bkColor: bkColor
      )
      DispatchQueue.main.async {
        completion(resultImage)
      }
    }
  }

  /// 同步生成二维码/条形码的私有方法，使用UIGraphicsImageRenderer
  private static func createCodeSync(
    type: UIImage.CICodeGeneratorType = .QRCode,
    string: String,
    size: CGSize,
    qrColor: UIColor = .black,
    bkColor: UIColor = .white
  ) -> UIImage? {
    guard let stringData = string.data(using: .utf8) else {
      return nil
    }
          
    let qrFilter = CIFilter(name: type.rawValue)
    qrFilter?.setValue(stringData, forKey: "inputMessage")
    // 设置二维码的纠错水平 L:7% H:30%
    qrFilter?.setValue("L", forKey: "inputCorrectionLevel")
          
    // 上色
    guard let qrOutputImage = qrFilter?.outputImage else {
      return nil
    }
          
    let colorFilter = CIFilter(name: "CIFalseColor",
                               parameters: [
                                 "inputImage": qrOutputImage,
                                 "inputColor0": CIColor(cgColor: qrColor.cgColor),
                                 "inputColor1": CIColor(cgColor: bkColor.cgColor),
                               ])
    guard let colorOutputImage = colorFilter?.outputImage,
          let cgImage = CIContext().createCGImage(colorOutputImage, from: colorOutputImage.extent)
    else {
      return nil
    }
    let renderer = UIGraphicsImageRenderer(size: size)
    return renderer.image { context in
      let cgContext = context.cgContext
      cgContext.interpolationQuality = .none
      cgContext.scaleBy(x: 1.0, y: -1.0)
      cgContext.draw(cgImage, in: cgContext.boundingBoxOfClipPath)
    }
  }
}
